package vn.pyco.prez.tapestry.components;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;

import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.Link;
import org.apache.tapestry5.StreamResponse;
import org.apache.tapestry5.annotations.OnEvent;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.annotations.SetupRender;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import vn.pyco.prez.io.PNGInline;

import com.gc.iotools.stream.is.InputStreamFromOutputStream;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;

public class QRCode {
	private final static Logger logger = LoggerFactory.getLogger(QRCode.class);
	
	@Parameter
	@Property
	private int _height;
	
	@Parameter
	@Property
	private int _width;
	
	@Parameter(defaultPrefix=BindingConstants.LITERAL)
	private String _data;

	@Persist
	private String _dataToDisplay;
	
	@Inject
	private ComponentResources resources;
	
	@SetupRender
	public void setupRender(){
		_dataToDisplay = _data;
		logger.debug("Data to Encode : " + _data);
	}
	
	
	@OnEvent(value="image")
	public StreamResponse onImage(){
		final String data = _dataToDisplay; 

		@SuppressWarnings("rawtypes")
		final InputStreamFromOutputStream in = new InputStreamFromOutputStream() {
			@Override
			protected Object produce(OutputStream out) throws Exception {
				encoreQR(out,data);
				return null;
			}

		};

  		return new PNGInline(in,"qrcode");
	}
	
	public Link getLink() {
	    return resources.createEventLink("image");
	}

	
	private void encoreQR(OutputStream image, String dataToDisplay){
	    Charset charset = Charset.forName("ISO-8859-1");
	    CharsetEncoder encoder = charset.newEncoder();
	    byte[] b = null;
	    String data;
	    // get a byte matrix for the data
	    BitMatrix matrix = null;
	    com.google.zxing.Writer writer = new QRCodeWriter();
	    
	    try {
	    	// Convert a string to ISO-8859-1 bytes in a ByteBuffer
	        ByteBuffer bbuf = encoder.encode(CharBuffer.wrap(dataToDisplay));
	        b = bbuf.array();
	        data = new String(b, "ISO-8859-1");
	        matrix = writer.encode(data, com.google.zxing.BarcodeFormat.QR_CODE, _width, _height);
	        MatrixToImageWriter.writeToStream(matrix, "PNG", image);
	        
	    } catch (com.google.zxing.WriterException e) {
	    	logger.error(e.getMessage(), e);
	    } catch (CharacterCodingException e) {
	    	logger.error(e.getMessage(), e);
	    } catch (UnsupportedEncodingException e) {
	    	logger.error(e.getMessage(), e);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}

	}

}
